#include <gio/gnetworking.h>
#include <libsoup/soup.h>
#define LOCAL_PORT 8888
static void
on_text_message (SoupWebsocketConnection *connection,
    SoupWebsocketDataType type,
    GBytes *message,
    gpointer user_data)
{
  gsize len;
  const gchar *data = g_bytes_get_data(message, &len);

  if (type == SOUP_WEBSOCKET_DATA_TEXT) {
    g_print("Received WebSocket message: %.*s\n", (int)len, data);
    soup_websocket_connection_send_text (connection, data);
  }
}
static void
on_close_unref_connection (SoupWebsocketConnection *connection,
    gpointer user_data)
{
  g_print("WebSocket connection closed\n");
  g_clear_object (&connection);
}
static void
got_server_connection (SoupServer *server,
    SoupWebsocketConnection *connection,
    const char *path,
    SoupClientContext *context,
    gpointer user_data)
{
  g_print("WebSocket connected\n");

  g_object_ref (connection);
  g_signal_connect(connection, "message", G_CALLBACK(on_text_message), NULL);
  g_signal_connect(connection, "closed", G_CALLBACK(on_close_unref_connection),
      NULL);
}
static void
server_request_started (SoupServer *server,
    SoupMessage *msg,
    SoupClientContext *client,
    gpointer user_data)
{
  g_print ("%s\n", msg->request_body->data);
}
static void
forget_close (SoupMessage *msg, gpointer user_data)
{
  soup_message_headers_remove (msg->response_headers, "Connection");
}

static void
close_socket (SoupMessage *msg, gpointer user_data)
{
  SoupSocket *sock = user_data;
  int sockfd;
  sockfd = soup_socket_get_fd (sock);
  shutdown (sockfd, SHUT_WR);
  soup_message_body_append (msg->response_body, SOUP_MEMORY_STATIC,
                            "foo", 3);
}

static void
timeout_socket (SoupSocket *sock, gpointer user_data)
{
  soup_socket_disconnect (sock);
}
static void
timeout_request_started (SoupServer *server, SoupMessage *msg,
                         SoupClientContext *client, gpointer user_data)
{
  SoupSocket *sock;
  GMainContext *context = g_main_context_get_thread_default ();
  guint readable;

  g_signal_handlers_disconnect_by_func (server, timeout_request_started, NULL);

  G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
  sock = soup_client_context_get_socket (client);
  G_GNUC_END_IGNORE_DEPRECATIONS;
  readable = g_signal_connect (sock, "readable",
                              G_CALLBACK (timeout_socket), NULL);

  while (soup_socket_is_connected (sock))
          g_main_context_iteration (context, TRUE);
  g_signal_handler_disconnect (sock, readable);
}

static void
setup_timeout_persistent (SoupServer *server, SoupSocket *sock)
{
        char buf[1];
        gsize nread;

        soup_socket_read (sock, buf, 1, &nread, NULL, NULL);
        g_signal_connect (server, "request-started",
                          G_CALLBACK (timeout_request_started), NULL);
}


static void
server_callback (SoupServer *server, SoupMessage *msg,
    const char *path, GHashTable *query,
    SoupClientContext *context, gpointer data)
{
  if (msg->method != SOUP_METHOD_GET && msg->method != SOUP_METHOD_POST) {
    soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED);
    return;
  }

  if (g_str_has_prefix (path, "/content-length/")) {
    gboolean too_long = strcmp (path, "/content-length/long") == 0;
    gboolean no_close = strcmp (path, "/content-length/noclose") == 0;

    soup_message_set_status (msg, SOUP_STATUS_OK);
    soup_message_set_response (msg, "text/plain",
                               SOUP_MEMORY_STATIC, "foobar", 6);
    if (too_long)
      soup_message_headers_set_content_length (msg->response_headers, 9);
    soup_message_headers_append (msg->response_headers,
                                 "Connection", "close");

    if (too_long) {
      SoupSocket *sock;
      G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
      sock = soup_client_context_get_socket (context);
      G_GNUC_END_IGNORE_DEPRECATIONS;
      g_signal_connect (msg, "wrote-chunk",
                        G_CALLBACK (close_socket), sock);
    } else if (no_close) {
      g_signal_connect (msg, "wrote-headers",
                    G_CALLBACK (forget_close), NULL);
    }
      return;
  }

  if (!strcmp (path, "/timeout-persistent")) {
    SoupSocket *sock;

    G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
    sock = soup_client_context_get_socket (context);
    G_GNUC_END_IGNORE_DEPRECATIONS;
    setup_timeout_persistent (server, sock);
  }

  soup_message_set_status (msg, SOUP_STATUS_OK);
  soup_message_headers_append(msg->response_headers, "Access-Control-Allow-Origin", "*");

  soup_message_set_response (msg, "text/plain",
                             SOUP_MEMORY_STATIC, "index", 5);
  return;
}
int main()
{
  g_setenv ("G_MESSAGES_DEBUG", "all", TRUE);
  SoupServer *server = soup_server_new(SOUP_SERVER_SERVER_HEADER,
      "MyWebSocketServer", NULL);

  soup_server_add_handler(server, NULL, server_callback, "http", NULL);
  soup_server_add_websocket_handler(server, "/websocket", NULL,
      NULL, got_server_connection, NULL, NULL);
  ///soup_server_listen_all(server, 8888, 0, NULL);
  soup_server_listen_all(server, LOCAL_PORT, 0, NULL);
  g_debug ("local port:%d", LOCAL_PORT);

  GMainLoop *loop = g_main_loop_new(NULL, FALSE);

  g_main_loop_run(loop);
  g_main_loop_unref(loop);
  g_object_unref(server);

    return 0;
}
